#include <iostream>
#include <thread>
#include <list>
#include <mutex>
using namespace std;


/*
 P8 unique_lock详解
    (1)unique_lock 取代 lock_guard
    (2)unique_lockd 的第二个参数
        (2.1) std::adopt_lock
        (2.2)  std::try_to_lock
        (2.3)  std::defer_lock
    (3)unique_lockd 的成员函数
        (3.1) lock()
        (3.2) unlock()
        (3.3) try_lock()
        (3.4) release()
    (4)unique_lockd所有权的传递
*/
class MessageList
{
private:
    mutex my_mutex1;
    mutex my_mutex2;  //另外一个互斥量
    list<int> msgRecvQueue;
public:
    // 收集命令
    void inMsgRecvQueue()
    {
        for(int i=0;i<100000;i++)
        {
            // my_mutex1.lock();
            // my_mutex2.lock();    //
            std::unique_lock<std::mutex> sbguard(my_mutex1,std::try_to_lock);                                               // lock_guard 的析构函数 执行了mutex::unlock()
            if(sbguard.owns_lock())
            {
                cout<<"inMsgRecvQueue()执行,插入一个元素 : command= "<<i<<endl;
                msgRecvQueue.push_back(i);
            }
            else
            {
                cout<<"干点别的事"<<endl;
            }     
            // my_mutex2.unlock();  // 
            // my_mutex1.unlock();
        }
    }
    bool outMsgLULProc(int & command)
    {
        //临时对象 
        //std::lock_guard<std::mutex> sbguard(my_mutex); // lock_guard 的构造函数 执行了 mutex::lock()
        //my_mutex1.lock();
        //std::unique_lock<std::mutex> sbguard(my_mutex1,std::adopt_lock);     
        //std::unique_lock<std::mutex> sbguard(my_mutex1,std::adopt_lock);                                               // lock_guard 的析构函数 执行了mutex::unlock()
        std::unique_lock<std::mutex> sbguard(my_mutex1);                                               // lock_guard 的析构函数 执行了mutex::unlock()
        // my_mutex2.lock(); //
        // my_mutex1.lock();
        if(!msgRecvQueue.empty())
        {
            command = msgRecvQueue.front();
            msgRecvQueue.pop_front();
            // my_mutex1.unlock();
            // my_mutex2.unlock();  //
            return true;
        }
        // my_mutex1.unlock();
        // my_mutex2.unlock(); //
        return false;
    }
    void outMsgRecvQueue()
    {
        for(int i=0;i<100000;i++)
        {
            //my_mutex.lock();
            int command;
            if(outMsgLULProc(command))
            {
                //int command = msgRecvQueue.front(); //返回第一个元素，但不检查元素是否存在
                //msgRecvQueue.pop_front();
                cout<<"outMsgRecvQueue()执行,command = "<<command<<endl;
            }
            else
            {
                cout<<"outMsgRecvQueue()执行,但目前消息队列为空格"<<endl;
            }
            //my_mutex.unlock();
        }
        cout<<"outMsgRecvQueue()执行完成"<<endl;
    }
};

int main()
{
    // 保护共享数据 , 操作时把共享数据锁住，其他操作共享数据必须等待解锁
    /*(1) unique_lock 取代 lock_guard
        一般使用lock_guard 就可以了 
        std::unique_lock<std::mutex> sbguard(my_mutex1);     

    (2)unique_lockd 的第二个参数
        (2.1) std::adopt_lock
        std::unique_lock<std::mutex> sbguard(my_mutex1,std::adopt_lock);
        表示互斥量已经被lock了

        (2.2)  std::try_to_lock

        尝试用mutex 的lock的锁定mutex;
        但如果没有锁成功，也会立即返回，并不会阻塞
        std::unique_lock<std::mutex> sbguard(my_mutex1,std::try_to_lock);        // lock_guard 的析构函数 执行了mutex::unlock()
        if(sbguard.owns_lock())
        {

        }

        (2.3)  std::defer_lock
        std::unique_lock<std::mutex> sbguard(my_mutex1,std::defer_lock);
        //没有加锁的my_mutex1

        不能自己先lock,否则会报异常


    (3)unique_lock 的成员函数
        (3.1) lock()
            加锁
        (3.2) unlock()
            解锁
        (3.3) try_lock()
        (3.4) release()
            释放 mutex 的所有权，与 unique_lockd 不再有联系
            严格区别 unlock() 与 release() 的 区别

            接触联系后 一定要记得自己unlock
            std::unique_lock<std::mutex> sbguard(my_mutex1);
            std::mutex* ptx = sbguard.release();
            ptx->unlock();     // 一定要记得unlock

        锁的粒度 ：锁住的代码多少


    (4)unique_lockd所有权的传递
    unique_lockd所有权 可以移动 但不能复制
    std::unique_lock<std::mutex> sbguard1(my_mutex1);
    std::unique_lock<std::mutex> sbguard2(std::move(sbguard1));
    现在 sbguard1 指向空 解除与my_mutex1的关系
    */

    MessageList msgList;
    //第二个参数是引用，保证 线程里面使用的是用一个对象
    thread t1(&MessageList::inMsgRecvQueue,&msgList);
    thread t2(&MessageList::outMsgRecvQueue,&msgList);
    t1.join();
    t2.join();

}